home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AppsToGo / Kibitz / BoardSlider.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  17.6 KB  |  651 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        boardslider.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10. /* This is a custom slider for Kibitz.  It sends AppleEvents to the opponent,
  11. ** if there is one, so that the remote board is also scrolled.  It sends a
  12. ** maximum of 1 a second, so that they will be able to be processed without
  13. ** stacking up at the other end.
  14. **
  15. ** There is a custom cdef for this code.  All it does is jump to this code.
  16. ** There is a really good reason for this, which is most obscure.  It is
  17. ** possible that, when you choose an opponent machine, you choose your own
  18. ** machine.  This is fully supported in Kibitz.  As a matter of fact, only
  19. ** theMakeTarget code "knows" that it is the same machine.  The rest of the
  20. ** application is completely ignorant of this fact.  When the user clicks
  21. ** on the slider, the control manager locks down the cdef, and then calls it.
  22. ** When the custom cdef returns to the control manager, the cdef is unlocked.
  23. ** This all seems very reasonable.  However, in the case that you are sending
  24. ** a game to the same machine, I send an AppleEvent, which causes an update
  25. ** on the slider.  This update is handled by the control manager calling the
  26. ** cdef.  Of course, it locks it down, and then when the control manager is
  27. ** returned to, it unlocks it.  BUT WAIT!!  We are still tracking the slider
  28. ** that caused the AppleEvent to be sent, which in turn caused the slider of
  29. ** another window to update.  This is true.  It is also true that the cdef
  30. ** is now UNLOCKED!  And with AppleEvents using memory in a healthy way, it
  31. ** is very probable that the cdef will  move.  It isn't a good idea to rts
  32. ** to code that has moved.  This is why the cdef jumps to the code in the
  33. ** application.  We never return to the (potentially unlocked) cdef.  We
  34. ** return straight to the control manager.  Ugly problem, huh? */
  35.  
  36.  
  37.  
  38. /*****************************************************************************/
  39.  
  40.  
  41.  
  42. #define kCapHeight        11
  43. #define kThumbHeight    7
  44. #define kThumbOffset    12
  45. #define kSliderWidth    13
  46.  
  47. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  48. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  49. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  50.  
  51. #ifndef __GWLAYERS__
  52. #include <GWLayers.h>
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __TOOLUTILS__
  60. #include <ToolUtils.h>
  61. #endif
  62.  
  63. #ifndef __UTILITIES__
  64. #include <Utilities.h>
  65. #endif
  66.  
  67.  
  68.  
  69. /*****************************************************************************/
  70.  
  71.  
  72.  
  73. #ifdef powerc
  74. #pragma options align=mac68k
  75. #endif
  76. typedef struct cdefRsrcJMP {
  77.     long    jsrInst;
  78.     long    moveInst;
  79.     short    jmpInst;
  80.     long    jmpAddress;
  81. } cdefRsrcJMP;
  82. typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
  83. #if defined(powerc) || defined(__powerc)
  84. #pragma options align=reset
  85. #endif
  86.  
  87. #ifdef powerc
  88. #pragma options align=mac68k
  89. #endif
  90. typedef struct thumbCntlParams {
  91.     Rect    limitRect;
  92.     Rect    slopRect;
  93.     short    axis;
  94. } thumbCntlParams;
  95. #if defined(powerc) || defined(__powerc)
  96. #pragma options align=reset
  97. #endif
  98.  
  99.  
  100.  
  101. static void            BoardDrawCIcon(CIconHandle iconHndl, short hloc, short vloc);
  102. static pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm);
  103. static void            BoardSliderUpdate(ControlHandle ctl, short hiliteCap);
  104. static Rect            CalcSliderRect(ControlHandle ctl);
  105. static void            TrackSlider(ControlHandle ctl, Point origMouseLoc);
  106.  
  107.  
  108.  
  109. /*****************************************************************************/
  110. /*****************************************************************************/
  111.  
  112. #if applec
  113. #pragma segment Controls
  114. #endif
  115.  
  116. /*****************************************************************************/
  117. /*****************************************************************************/
  118.  
  119.  
  120.  
  121. /* Given a file reference, adjust the slider to reflect the position
  122. ** of the chessboard. */
  123.  
  124. void    AdjustGameSlider(FileRecHndl frHndl)
  125. {
  126.     ControlHandle    ctl;
  127.     short            val, max;
  128.     WindowPtr        oldPort;
  129.  
  130.     ctl = (*frHndl)->doc.gameSlider;
  131.     val = (*frHndl)->doc.gameIndex;
  132.     max = (*frHndl)->doc.numGameMoves;
  133.         /* Get the info we need. */
  134.  
  135.     (*ctl)->contrlMax   = max;
  136.     (*ctl)->contrlValue = val;
  137.     oldPort = SetFilePort(frHndl);
  138.     BoardSliderUpdate(ctl, -1);
  139.         /* Change the slider value and show the result. */
  140.  
  141.     SetPort(oldPort);
  142. }
  143.  
  144.  
  145.  
  146. /*****************************************************************************/
  147.  
  148.  
  149.  
  150. ControlHandle    BoardSliderNew(WindowPtr window)
  151. {
  152.     WindowPtr        oldPort;
  153.     FileRecHndl        frHndl;
  154.     Rect            boardRect;
  155.     ControlHandle    sliderCtl;
  156.     cdefRsrcJMPHndl    cdefRsrc;
  157.     static    ControlDefUPP    boardSliderCtlUPP = nil;
  158.  
  159.     GetPort(&oldPort);
  160.     SetPort(window);
  161.  
  162.     frHndl = (FileRecHndl)GetWRefCon(window);
  163.  
  164.     boardRect = BoardRect();
  165.     boardRect.left    = boardRect.right + 4;
  166.     boardRect.right   = boardRect.left + 13;
  167.     boardRect.top    += 4;
  168.     boardRect.bottom -= 4;
  169.  
  170.     cdefRsrc = (cdefRsrcJMPHndl)GetResource('CDEF', (rSliderCtl / 16));
  171.     if (!boardSliderCtlUPP)
  172.         boardSliderCtlUPP = NewControlDefProc(BoardSliderCtl);
  173.     (*cdefRsrc)->jmpAddress = (long)boardSliderCtlUPP;
  174.     FlushInstructionCache();
  175.         /* Make sure that instruction caches don't kill us. */
  176.  
  177.     sliderCtl = NewControl(window, &boardRect, "\p", true, 0, 0, 0,
  178.                            rSliderCtl, (long)frHndl);
  179.  
  180.     return(sliderCtl);
  181. }
  182.  
  183.  
  184.  
  185. /*****************************************************************************/
  186.  
  187.  
  188.  
  189. pascal long    BoardSliderCtl(short varCode, ControlHandle ctl, short msg, long parm)
  190. {
  191. #ifndef __MWERKS__
  192. #pragma unused (varCode)
  193. #endif
  194.  
  195.     Rect            viewRect, sliderRect;
  196.     thumbCntlParams    *tcp;
  197.     static Point    lastClick;
  198.  
  199.     viewRect = (*ctl)->contrlRect;
  200.  
  201.     switch (msg) {
  202.         case drawCntl:
  203.             BoardSliderUpdate(ctl, -1);
  204.             break;
  205.  
  206.         case testCntl:
  207.             if ((*ctl)->contrlHilite == 255) return(0);
  208.             if (!(*ctl)->contrlMax) return(0);
  209.             if (PtInRect(*(Point *)&parm, &viewRect)) {
  210.                 lastClick = *((Point *)&parm);
  211.                 return(inThumb);
  212.             }        /* Everything is the thumb.  The "thumb" routine will figure
  213.                     ** out what part it is.  Since this is a very specific control,
  214.                     ** we can get away with this simplification. */
  215.             return(0);
  216.  
  217.         case calcCRgns:
  218.         case calcCntlRgn:
  219.             if (msg == calcCRgns) parm &= 0x00FFFFFF;
  220.             RectRgn((RgnHandle)parm, &viewRect);
  221.             break;
  222.  
  223.         case initCntl:
  224.             break;
  225.  
  226.         case dispCntl:
  227.             break;
  228.  
  229.         case posCntl:
  230.             break;
  231.  
  232.         case thumbCntl:
  233.             sliderRect = (*ctl)->contrlRect;
  234.             tcp = (thumbCntlParams *)parm;
  235.             tcp->limitRect = sliderRect;
  236.             InsetRect(&sliderRect, -64, -64);
  237.             tcp->slopRect = sliderRect;
  238.             tcp->axis = 2;
  239. //            TrackSlider(ctl, lastClick);
  240.             break;
  241.  
  242.         case dragCntl:
  243.             TrackSlider(ctl, lastClick);
  244.             return(true);
  245.  
  246.         case autoTrack:
  247.             break;
  248.  
  249.         default:
  250.             break;
  251.     }
  252.  
  253.     return(0);
  254. }
  255.  
  256.  
  257.  
  258. /*****************************************************************************/
  259.  
  260.  
  261.  
  262. void    BoardSliderUpdate(ControlHandle ctl, short hiliteCap)
  263. {
  264.     Rect        ctlRect, workRect, sliderRect;
  265.     FileRecHndl    frHndl;
  266.     Boolean        active;
  267.     short        i, j, thumbColor;
  268.     RgnHandle    origClipRgn, clipRgn, workRgn;
  269.     CIconHandle    icons[7];
  270.  
  271.     /* We use color icons here for the various slider parts.  This is so that we
  272.     ** can take advantage of the depth of monitors.  I use icons here so that I
  273.     ** can do a single plot of an icon if the delta of the thumb is -12 to 12.
  274.     ** (The thumb is in the center of an icon, and 12 pixels above and below the
  275.     ** icon, I have slider bar.  Use RedEdit to check it out.)  This technique
  276.     ** gives a very smooth appearance when the thumb slides.  There is no flash.
  277.     ** For deltas greater than +-12, I redraw the slider without the thumb, and
  278.     ** then draw the thumb in the new position.  Since the thumb is moving a lot
  279.     ** anyway, this doesn't show up as a flicker.  There is no overlap in the
  280.     ** old and new positions for a big delta. */
  281.  
  282.     ctlRect = (*ctl)->contrlRect;
  283.     frHndl  = (FileRecHndl)GetControlReference(ctl);
  284.  
  285.     for (i = 0; i < 7; i++) icons[i] = ReadCIcon(i + rSliderBase);
  286.  
  287.     origClipRgn = NewRgn();
  288.     GetClip(origClipRgn);
  289.  
  290.     clipRgn = NewRgn();
  291.  
  292.     for (i = 0; i < 2; i++) {        /* Draw the arrow parts first. */
  293.         j = i;
  294.         if (hiliteCap == i) j += 5;
  295.         workRect = ctlRect;
  296.         if (!i)
  297.             workRect.bottom = workRect.top + kCapHeight;
  298.         else
  299.             workRect.top = workRect.bottom - kCapHeight;
  300.         RectRgn(clipRgn, &workRect);
  301.         SetClip(clipRgn);
  302.             /* Clip out the area outside the arrow part. */
  303.         BoardDrawCIcon(icons[j], workRect.left, workRect.top);
  304.             /* Draw the arrow part. */
  305.     }
  306.  
  307.     ctlRect.top    += kCapHeight;
  308.     ctlRect.bottom -= kCapHeight;
  309.     RectRgn(clipRgn, &ctlRect);
  310.     SetClip(clipRgn);
  311.         /* Clip out everything except the slider bar area. */
  312.  
  313.     active  = ((*ctl)->contrlOwner == FrontWindow());
  314.     if ((*ctl)->contrlHilite == 255) active = false;
  315.     if (!(*ctl)->contrlMax) active = false;
  316.  
  317.     if (active) {        /* If control active, draw the thumb. */
  318.         sliderRect = CalcSliderRect(ctl);
  319.         thumbColor = (((*ctl)->contrlValue & 0x01) ^ (*frHndl)->doc.startColor);
  320.         BoardDrawCIcon(icons[3 + thumbColor],
  321.                        sliderRect.left, sliderRect.top - kThumbOffset);
  322.         workRgn = NewRgn();
  323.         RectRgn(workRgn, &sliderRect);
  324.         DiffRgn(clipRgn, workRgn, clipRgn);
  325.         SetClip(clipRgn);
  326.         DisposeRgn(workRgn);
  327.             /* Now that the thumb is drawn, protect it by clipping it out. */
  328.     }
  329.  
  330.     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  331.         BoardDrawCIcon(icons[2], ctlRect.left, i);
  332.             /* Draw the slider bar portion. */
  333.  
  334.     /* It is now completely drawn.  Clean up and get out. */
  335.  
  336.     SetClip(origClipRgn);
  337.     DisposeRgn(clipRgn);
  338.     DisposeRgn(origClipRgn);
  339.  
  340.     for (i = 0; i < 7; i++) KillCIcon(icons[i]);
  341. }
  342.  
  343.  
  344.  
  345. /*****************************************************************************/
  346.  
  347.  
  348.  
  349. void    BoardDrawCIcon(CIconHandle iconHndl, short hloc, short vloc)
  350. {
  351.     Rect    iconRect;
  352.  
  353.     iconRect.right  = (iconRect.left = hloc) + 32;
  354.     iconRect.bottom = (iconRect.top  = vloc) + 32;
  355.  
  356.     DrawCIcon(iconHndl, iconRect);
  357. }
  358.  
  359.  
  360.  
  361. /*****************************************************************************/
  362.  
  363.  
  364.  
  365. Rect    CalcSliderRect(ControlHandle ctl)
  366. {
  367.     Rect    ctlRect, sliderRect;
  368.     short    max, val;
  369.     long    calc;
  370.  
  371.     ctlRect = (*ctl)->contrlRect;
  372.     ctlRect.top    += kCapHeight;
  373.     ctlRect.bottom -= kCapHeight;
  374.     max = (*ctl)->contrlMax;
  375.     val = (*ctl)->contrlValue;
  376.  
  377.     calc = ctlRect.bottom - ctlRect.top - kThumbHeight;
  378.     calc *= val;
  379.     if (max) calc /= max;
  380.     sliderRect.top    = ctlRect.top + calc,
  381.     sliderRect.left   = ctlRect.left;
  382.     sliderRect.bottom = sliderRect.top + kThumbHeight;
  383.     sliderRect.right  = ctlRect.right;
  384.  
  385.     return(sliderRect);
  386. }
  387.  
  388.  
  389.  
  390. /*****************************************************************************/
  391.  
  392.  
  393.  
  394. void    TrackSlider(ControlHandle ctl, Point origMouseLoc)
  395. {
  396.     CIconHandle    icons[7];
  397.     WindowPtr    oldPort;
  398.     Rect        ctlRect, sliderRange, slopRect, sliderRect, capRect, pgRect;
  399.     FileRecHndl    frHndl;
  400.     RgnHandle    origClipRgn, clipRgn, workRgn;
  401.     short        i, max, val, origGameIndex, ovloc, voffset, vloc, delta, hiliteCap;
  402.     Boolean        twoPlayer, hiliteOn, doPgScroll;
  403.     long        origTick, tick, calc;
  404.     Point        lastMouseLoc, mouseLoc;
  405.  
  406.     /* Get everything we need set up. */
  407.  
  408.     origTick = tick = TickCount();
  409.  
  410.     for (i = 2; i < 5; i++) icons[i] = ReadCIcon(i + rSliderBase);
  411.  
  412.     frHndl  = (FileRecHndl)GetControlReference(ctl);
  413.     oldPort = SetFilePort(frHndl);
  414.     ctlRect = (*ctl)->contrlRect;
  415.  
  416.     origClipRgn = NewRgn();
  417.     GetClip(origClipRgn);
  418.  
  419.     clipRgn = NewRgn();
  420.     workRgn = NewRgn();
  421.  
  422.     origGameIndex = (*frHndl)->doc.gameIndex;
  423.     max = (*ctl)->contrlMax;
  424.  
  425.     twoPlayer  = (*frHndl)->doc.twoPlayer;
  426.     sliderRect = CalcSliderRect(ctl);
  427.  
  428.     /* That ought to be enough setup. */
  429.  
  430.     if (PtInRect(origMouseLoc, &sliderRect)) {    /* If they are on the thumb... */
  431.  
  432.         ctlRect.top    += kCapHeight;            /* Protect the arrow parts. */
  433.         ctlRect.bottom -= kCapHeight;
  434.         RectRgn(clipRgn, &ctlRect);
  435.         SetClip(clipRgn);
  436.  
  437.         sliderRange = ctlRect;                    /* Calc area thumb can move. */
  438.         sliderRange.bottom -= kThumbHeight;        /* Count height of thumb against range. */
  439.  
  440.         slopRect = sliderRange;                    /* Give the user some slop. */
  441.         InsetRect(&slopRect, -20, -20);
  442.  
  443.         lastMouseLoc = origMouseLoc;
  444.         voffset = lastMouseLoc.v - sliderRect.top;
  445.         ovloc   = lastMouseLoc.v - voffset;
  446.  
  447.         while (StillDown()) {
  448.  
  449.             if (tick + 30 < TickCount()) {        /* Send max 1 AppleEvent per 1/2 sec. */
  450.                 tick = TickCount();
  451.                 if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  452.             }
  453.  
  454.             GetMouse(&mouseLoc);
  455.             if (!EqualPt(mouseLoc, lastMouseLoc)) {        /* The mouse has moved. */
  456.  
  457.                 if (!PtInRect(mouseLoc, &slopRect)) mouseLoc = origMouseLoc;
  458.                     /* Outside slopRect, so snap back to the original position. */
  459.  
  460.                 vloc = mouseLoc.v - voffset;
  461.                 if (vloc < sliderRange.top)    vloc = sliderRange.top;
  462.                 if (vloc > sliderRange.bottom) vloc = sliderRange.bottom;
  463.                 delta = vloc - ovloc;
  464.                     /* The delta tells us how much the thumb moved. */
  465.  
  466.                 if (
  467.                     (delta < -((32 - kThumbHeight) / 2)) ||
  468.                     (delta >  ((32 - kThumbHeight) / 2))
  469.                 ) {
  470.                     for (i = ctlRect.top; i < ctlRect.bottom; i += 32)
  471.                         BoardDrawCIcon(icons[2], ctlRect.left, i);
  472.                             /* The thumb moved too far for a single plot to cover
  473.                             ** up the old position, so clear the old thumb. */
  474.                 }
  475.  
  476.                 calc  = max + 1;        /* Force below math to be with longs. */
  477.                 calc *= (vloc - sliderRange.top);
  478.                     /* We use max + 1 because there is one more game
  479.                     ** move position than moves in the game.  This is
  480.                     ** because we can position in front of the first move,
  481.                     ** as well as after the last move. */
  482.                 calc /= (sliderRange.bottom - sliderRange.top);
  483.  
  484.                 val = calc;
  485.                 if (val > max) val = max;
  486.                 if (val < 0)   val = 0;
  487.                 if (delta)
  488.                     BoardDrawCIcon(icons[3 + ((val + (*frHndl)->doc.startColor) & 0x01)],
  489.                                    ctlRect.left, vloc - kThumbOffset);
  490.                                         /* The thumb is now updated. */
  491.  
  492.                 SetClip(origClipRgn);
  493.                 RepositionBoard(frHndl, val, true);
  494.                     /* We set the clipRgn back to the original so the board
  495.                     ** can update.  (Pretty boring if it doesn't. */
  496.  
  497.                 SetClip(clipRgn);
  498.                     /* Back to our normally scheduled program... */
  499.  
  500.                 lastMouseLoc = mouseLoc;
  501.                 (*ctl)->contrlValue = val;
  502.                 ovloc = vloc;
  503.             }
  504.         }
  505.     }
  506.  
  507.     else {        /* We missed the thumb.  See if we hit an arrow part... */
  508.         delta = hiliteOn = 0;
  509.         capRect = ctlRect;
  510.         capRect.bottom = ctlRect.top + kCapHeight;
  511.         if (PtInRect(origMouseLoc, &capRect)) {
  512.             delta = -1;
  513.             hiliteCap = 0;
  514.         }
  515.         else {
  516.             capRect = ctlRect;
  517.             capRect.top = ctlRect.bottom - kCapHeight;
  518.             if (PtInRect(origMouseLoc, &capRect)) {
  519.                 delta = 1;
  520.                 hiliteCap = 1;
  521.             }
  522.         }
  523.  
  524.         if (delta) {    /* We hit an arrow, and there is a change to do... */
  525.             do {
  526.                 if (tick + 30 < TickCount()) {
  527.                     tick = TickCount();
  528.                     if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  529.                 }
  530.                 GetMouse(&mouseLoc);
  531.                 if (PtInRect(mouseLoc, &capRect)) {        /* Still in arrow... */
  532.                     val = (*ctl)->contrlValue + delta;
  533.                     if ((val >= 0) && (val <= max)) {    /* Still scrolling... */
  534.                         hiliteOn = true;
  535.                         (*ctl)->contrlValue = val;
  536.                         BoardSliderUpdate(ctl, hiliteCap);
  537.                         SetClip(origClipRgn);
  538.                         if (RepositionBoard(frHndl, val, true)) SetClip(clipRgn);
  539.                     }
  540.                     else {        /* Scrolled as far as we can go, so unhilite arrow. */
  541.                         if (hiliteOn) {
  542.                             BoardSliderUpdate(ctl, -1);
  543.                             hiliteOn = false;
  544.                         }
  545.                     }
  546.                 }
  547.                 else {        /* Outside arrow, so unhilite it. */
  548.                     if (hiliteOn) {
  549.                         BoardSliderUpdate(ctl, -1);
  550.                         hiliteOn = false;
  551.                     }
  552.                 }
  553.  
  554.                 while ((StillDown()) && (origTick + 20 > TickCount())) {};
  555.                     /* Don't go too fast. */
  556.  
  557.             } while (StillDown());
  558.         }
  559.  
  560.         else {
  561.  
  562.             pgRect = ctlRect;
  563.             pgRect.top    += kCapHeight;
  564.             pgRect.bottom -= kCapHeight;
  565.             if (PtInRect(origMouseLoc, &pgRect)) {        /* If in the page area... */
  566.                 delta = (origMouseLoc.v < sliderRect.top) ? -2 : 2;
  567.                 InsetRect(&pgRect, -10, -10);
  568.                 do {
  569.                     if (tick + 30 < TickCount()) {
  570.                         tick = TickCount();
  571.                         if (twoPlayer) SendGame(frHndl, kScrolling, nil);
  572.                     }
  573.                     GetMouse(&mouseLoc);
  574.                     if (PtInRect(mouseLoc, &pgRect)) {        /* Still in page area... */
  575.                         doPgScroll = false;
  576.                         sliderRect = CalcSliderRect(ctl);
  577.                         if ((delta == -2) && (mouseLoc.v < sliderRect.top))    doPgScroll = true;
  578.                         if ((delta == 2)  && (mouseLoc.v > sliderRect.bottom)) doPgScroll = true;
  579.                         if (doPgScroll) {
  580.                             val = (*ctl)->contrlValue + delta;
  581.                             if (val == -1)       val = 0;
  582.                             if (val == (max + 1)) val = max;
  583.                             if ((val >= 0) && (val <= max)) {    /* Still scrolling... */
  584.                                 (*ctl)->contrlValue = val;
  585.                                 BoardSliderUpdate(ctl, -1);
  586.                                 SetClip(origClipRgn);
  587.                                 if (RepositionBoard(frHndl, val, true)) SetClip(clipRgn);
  588.                             }
  589.                         }
  590.                     }
  591.  
  592.                     while ((StillDown()) && (origTick + 20 > TickCount())) {};
  593.                         /* Don't go too fast. */
  594.  
  595.                 } while (StillDown());
  596.             }
  597.         }
  598.     }
  599.  
  600.     SetClip(origClipRgn);
  601.     DisposeRgn(workRgn);
  602.     DisposeRgn(clipRgn);
  603.     DisposeRgn(origClipRgn);
  604.  
  605.     if (twoPlayer) SendGame(frHndl, kResync, nil);
  606.         /* Make sure that the result from the scroll isn't ignored.  The
  607.         ** opponent may ignore the events while we are scrolling, but not
  608.         ** when we are done. */
  609.  
  610.     BoardSliderUpdate(ctl, -1);
  611.         /* Snap the slider to a move position.  The user may have let go of the
  612.         ** slider at a position that doesn't map exactly to the game position. */
  613.  
  614.     for (i = 2; i < 5; i++) KillCIcon(icons[i]);
  615.  
  616.     SetPort(oldPort);
  617. }
  618.  
  619.  
  620.  
  621. /*****************************************************************************/
  622.  
  623.  
  624.  
  625. Boolean    RepositionBoard(FileRecHndl frHndl, short newPos, Boolean update)
  626. {
  627.     short        oldPos, delta;
  628.  
  629.     oldPos = (*frHndl)->doc.gameIndex;
  630.     if (newPos == oldPos) return(false);
  631.  
  632.     delta  = (newPos > oldPos) ? 1 : -1;
  633.         /* We need to walk the board forward or backward delta number of moves. */
  634.  
  635.     for (; oldPos != newPos; oldPos += delta)
  636.         MakeMove(frHndl, delta, 0, 0);
  637.             /* Walk the board position one half-move forward or backward. */
  638.  
  639.     if (update) {
  640.         ImageDocument(frHndl, true);
  641.         DrawButtonTitle(frHndl, (*frHndl)->doc.twoPlayer);
  642.         UpdateGameStatus(frHndl);
  643.             /* Show the new board position. */
  644.     }
  645.  
  646.     return(true);
  647. }
  648.  
  649.  
  650.  
  651.